local EmoTalentUtil = require "packages.emopack.pkg.emopack_talent.util" -- 加载战法核心
local skel = require "packages.emopack.pkg.emopack_talent.talents.core" ---@type SkillSkeleton

local hasTalent = EmoTalentUtil.hasTalent
local logTalent = EmoTalentUtil.logTalent
local invokeTalent = EmoTalentUtil.invokeTalent
local forRandom = EmoTalentUtil.forRandom
local getTalents = EmoTalentUtil.getTalents
local discoverTalent = EmoTalentUtil.discoverTalent
local handleInvokedTalents = EmoTalentUtil.handleInvokedTalents
local timesCheckFilter = EmoTalentUtil.timesCheckFilter


skel:addEffect(fk.AfterCardsMove, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local room = player.room
    local cost_data = {}
    local peach = 0
    local getNum, drawNum, loseNum, loseHandNum = 0, 0, 0, 0 -- 我获得牌数，摸牌数，失去牌数，失去手牌数
    local yiwenNum, youhuoNum, zoudiNum = 0, 0, 0
    local toDiscardNum = 0 -- 进入弃牌堆牌数
    local yaziTos, guileiTos, diebaoInfos = {}, {}, {}
    local loseAllHand = (data.extra_data or {}).loseAllHand or {}
    for _, move in ipairs(data) do
      if hasTalent(player, "emot_jufeng") and move.from == player and table.find(move.moveInfo, function(info) -- 飓风
        return info.fromArea == Card.PlayerEquip end) then
        table.insert(cost_data, "emot_jufeng")
      end
      if hasTalent(player, "emot_youbei") and move.from == player and player ~= room.current and -- 有备无患
      table.find(move.moveInfo, function(info)  return info.fromArea == Card.PlayerEquip end) then
        table.insert(cost_data, "emot_youbei")
      end
      if move.toArea == Card.DiscardPile then
        toDiscardNum = toDiscardNum + #move.moveInfo
      end
      if move.from == player then
        for _, info in ipairs(move.moveInfo) do
          if info.fromArea == Card.PlayerHand then -- 我失去手牌
            loseHandNum = loseHandNum + 1
            if move.moveReason ~= fk.ReasonUse then -- 疫蚊
              yiwenNum = yiwenNum + 1
            end
          end
          if info.fromArea == Card.PlayerEquip or info.fromArea == Card.PlayerHand then -- 我失去牌
            loseNum = loseNum + 1
            if move.toArea == Player.Hand and move.to and not move.to.dead and player:isEnemy(move.to) then -- 睚眦必报
              table.insertIfNeed(yaziTos, move.to)
            end
            if move.moveReason == fk.ReasonDiscard and move.proposer and not move.proposer.dead and player:isEnemy(move.proposer) then
              table.insertIfNeed(yaziTos, move.proposer)
            end
            if Fk:getCardById(info.cardId).trueName == "peach" then -- 结痂
              peach = peach + 1
            end
            if move.moveReason == fk.ReasonDiscard and not player.dead then -- 我弃置牌
              if hasTalent(player, "emot_chongcao") and player:getMark("emot_chongcao") == 0 then
                table.insertIfNeed(cost_data, "emot_chongcao")
              end
              if Fk:getCardById(info.cardId).color == Card.Black then -- 走地菇
                zoudiNum = zoudiNum + 1
              end
            end
          end
        end
      else
        for _, info in ipairs(move.moveInfo) do
          if info.fromArea == Card.PlayerEquip or info.fromArea == Card.PlayerHand then -- 其他角色失去牌
            if move.moveReason == fk.ReasonDiscard and player == room.current then
              youhuoNum = youhuoNum + 1
            end
          end
        end
      end
      if move.to == player and move.toArea == Card.PlayerHand then
        getNum = getNum + #move.moveInfo
        for _, info in ipairs(move.moveInfo) do
          if info.fromArea == Card.DrawPile then
            drawNum = drawNum + 1
          end
        end
      end
      -- 虫族女王
      if hasTalent(player, "emot_chonghuang") and not player.dead and move.moveReason == fk.ReasonDraw and #move.moveInfo > 2
      and move.to and player:isEnemy(move.to) and move.toArea == Card.PlayerHand then
        cost_data["emot_chonghuang"] = move.to
        table.insert(cost_data, "emot_chonghuang")
      end
      -- 诡雷
      if hasTalent(player, "emot_guilei") and not player.dead and move.moveReason == fk.ReasonDiscard
      and move.from and not move.from.dead and player:isEnemy(move.from)
      and table.find(move.moveInfo, function(info)
        return (info.fromArea == Card.PlayerEquip or info.fromArea == Card.PlayerHand) and info.beforeCard.suit == Card.Club
      end) then
        table.insertIfNeed(guileiTos, move.from)
      end
      -- 谍报
      if move.to and move.toArea == Card.PlayerHand and hasTalent(player, "emot_diebao") and not player.dead
       and player:isEnemy(move.to) and not move.to.dead then
        diebaoInfos[move.to] = diebaoInfos[move.to] or {}
        for _, info in ipairs(move.moveInfo) do
          table.insert(diebaoInfos[move.to], info.cardId)
        end
      end
    end
    --- 处理各种战法 ---
    if not player.dead and hasTalent(player, "emot_shenlu") and table.contains(loseAllHand, player) then -- 神鹿
      table.insert(cost_data, "emot_shenlu")
    end
    if hasTalent(player, "emot_zoudi") and zoudiNum > 0 then -- 走地菇
      cost_data["emot_zoudi"] = zoudiNum
      table.insert(cost_data, "emot_zoudi")
    end
    if not player.dead and hasTalent(player, "emot_gamma") then -- 伽玛
      local tos = table.filter(loseAllHand, function(to) return player:isEnemy(to) and not to.dead end)
      if #tos > 0 then
        cost_data["emot_gamma"] = tos
        table.insert(cost_data, "emot_gamma")
      end
    end
    if (peach > 0) and hasTalent(player, "emot_jiejia") and not player.dead then -- 结痂
      cost_data["emot_jiejia_peach"] = peach
      table.insert(cost_data, "emot_jiejia")
    end
    if #yaziTos > 0 and hasTalent(player, "emot_yazi") and not player.dead then -- 睚眦必报
      cost_data["emot_yazi"] = yaziTos
      table.insert(cost_data, "emot_yazi")
    end
    if yiwenNum > 0 and hasTalent(player, "emot_yiwen") then -- 疫蚊
      cost_data["emot_yiwen"] = yiwenNum
      table.insert(cost_data, "emot_yiwen")
    end
    if drawNum > 0 and hasTalent(player, "emot_shijieshu") and not player.dead then -- 世界树
      cost_data["emot_shijieshu"] = drawNum
      table.insert(cost_data, "emot_shijieshu")
    end
    if #guileiTos > 0 then -- 诡雷目标
      cost_data["emot_guilei"] = guileiTos
      table.insert(cost_data, "emot_guilei")
    end
    if next(diebaoInfos) ~= nil then -- 谍报目标
      cost_data["emot_diebao"] = diebaoInfos
      table.insert(cost_data, "emot_diebao")
    end
    if youhuoNum > 0 and hasTalent(player, "emot_youhuo") and not player.dead then -- 诱惑
      cost_data["emot_youhuo"] = youhuoNum
      table.insert(cost_data, "emot_youhuo")
    end
    if hasTalent(player, "emot_yinhang") then -- 银行家天赋会不停触发，无敌了
      --table.insert(cost_data, "emot_yinhang")
    end
    if getNum > 0 and hasTalent(player, "emot_yifu") then -- 疫蝠
      cost_data["emot_yifu"] = getNum
      table.insert(cost_data, "emot_yifu")
    end
    if toDiscardNum > 0 and hasTalent(player, "emot_jingluo") and not player.dead then -- 鲸落
      cost_data["emot_jingluo"] = toDiscardNum
      table.insert(cost_data, "emot_jingluo")
    end
    if getNum == 2 and hasTalent(player, "emot_tanglang") then -- 铁镰螳螂
      table.insert(cost_data, "emot_tanglang")
    end
    if (getNum > 0 or loseHandNum > 0) and hasTalent(player, "emot_shenjing") and player:getHandcardNum() == 2 then -- 神经元件
      table.insert(cost_data, "emot_shenjing")
    end
    if loseNum >= 5 and hasTalent(player, "emot_shanbeng") then -- 山崩地裂
      table.insert(cost_data, "emot_shanbeng")
    end
    if loseNum >= 2 and hasTalent(player, "emot_jiachong") then -- 水晶甲虫
      table.insert(cost_data, "emot_jiachong")
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cost_data = event:getCostData(self) or {}
    local getRandomEnemy = function()
      local targets = table.filter(room.alive_players, function(p) return player:isEnemy(p) end)
      if #targets > 0 then
        return table.random(targets)
      end
    end
    if table.contains(cost_data, "emot_chongcao") and not player.dead then -- 冬虫夏草
      invokeTalent(player, "emot_chongcao", event)
      room:setPlayerMark(player, "emot_chongcao", 1)
    end
    if table.contains(cost_data, "emot_youhuo") then -- 诱惑
      invokeTalent(player, "emot_youhuo", event)
      room:addPlayerMark(player, "emot_youhuo", cost_data["emot_youhuo"])
    end
    if table.contains(cost_data, "emot_diebao") then -- 谍报
      invokeTalent(player, "emot_diebao", event, true) -- 不log，太吵
      local diebaoInfos = cost_data["emot_diebao"] or {} ---@type table<ServerPlayer, string[]>
      for to, cards in pairs(diebaoInfos) do
        local mark = to:getTableMark("emot_diebao-turn")
        table.insertTable(mark, cards)
        room:setPlayerMark(to, "emot_diebao-turn", mark)
      end
    end
    -- 实际操作
    if table.contains(cost_data, "emot_chonghuang") and not player.dead then -- 虫族女王
      local to = cost_data["emot_chonghuang"] ---@type ServerPlayer
      if to and not to:isNude() then
        invokeTalent(player, "emot_chonghuang", event)
        local cards = table.random(to:getCardIds("he"), 2)
        room:obtainCard(player, cards, false, fk.ReasonPrey, player, skel.name)
        if not player.dead and table.find(cards, function(id)
          return Fk:getCardById(id).trueName == "slash"
        end) then
          discoverTalent(player, { style = {"worm", "poison"}, random = true })
        end
      end
    end
    if table.contains(cost_data, "emot_shijieshu") and not player.dead then -- 世界树
      local num = cost_data["emot_shijieshu"] or 0
      room:addPlayerMark(player, "emot_shijieshu", num)
      num = player:getMark("emot_shijieshu") // 5
      if num > 0 then
        invokeTalent(player, "emot_shijieshu", event)
        room:removePlayerMark(player, "emot_shijieshu", 5 * num)
        for _ = 1, num do
          discoverTalent(player, { rarity_limit = {1, 2}, random = true })
          if player.dead then break end
        end
      end
    end
    if table.contains(cost_data, "emot_shenlu") and not player.dead then -- 神鹿
      invokeTalent(player, "emot_shenlu", event)
      player:drawCards(5, skel.name)
    end
    if table.contains(cost_data, "emot_zoudi") and not player.dead then -- 走地菇
      invokeTalent(player, "emot_zoudi", event)
      local num = cost_data["emot_zoudi"] or 0
      local ids = room:getCardsFromPileByRule(".|.|diamond,heart", num, "allPiles")
      if #ids > 0 then
        room:obtainCard(player, ids, true, fk.ReasonPrey, player, skel.name)
      end
    end
    if table.contains(cost_data, "emot_jiachong") and not player.dead then -- 水晶甲虫
      local targets = table.filter(room.alive_players, function(p) return player:isEnemy(p) and p.shield > 0 end)
      if #targets > 0 then
        invokeTalent(player, "emot_jiachong", event)
        local to = table.random(targets)
        room:doIndicate(player, {to})
        local num = math.min(2, to.shield)
        room:changeShield(to, -num)
        room:changeShield(player, num)
        num = 2 - num
        if num > 0 then
          targets = table.filter(room.alive_players, function(p) return player:isEnemy(p) and p.shield > 0 end)
          if #targets > 0 then
            to = table.random(targets)
            room:doIndicate(player, {to})
            room:changeShield(to, -num)
            room:changeShield(player, num)
          end
        end
      end
    end
    if table.contains(cost_data, "emot_gamma") then -- 伽玛
      invokeTalent(player, "emot_gamma", event)
      local tos = cost_data["emot_gamma"] or {} ---@type ServerPlayer[]
      for _, to in ipairs(tos) do
        if not to.dead then
          room:doIndicate(player, {to})
          room:delay(100)
          room:changeMaxHp(to, -1)
        end
      end
    end
    if table.contains(cost_data, "emot_guilei") then -- 诡雷
      invokeTalent(player, "emot_guilei", event)
      local guileiTos = cost_data["emot_guilei"] or {} ---@type ServerPlayer[]
      for _, to in ipairs(guileiTos) do
        if not to.dead then
          room:doIndicate(player, {to})
          room:delay(200)
          room:damage { from = player, to = to, damage = 2, skillName = skel.name, damageType = fk.FireDamage }
        end
      end
    end
    if table.contains(cost_data, "emot_shanbeng") then -- 山崩地裂
      invokeTalent(player, "emot_shanbeng", event)
      for _, to in ipairs(room:getAllPlayers(true)) do
        if to and not to.dead and player:isEnemy(to) then
          room:delay(200)
          room:doIndicate(player, {to})
          room:damage { from = player, to = to, damage = 3, skillName = skel.name }
        end
      end
    end
    if table.contains(cost_data, "emot_jufeng") then -- 飓风
      invokeTalent(player, "emot_jufeng", event)
      for _ = 1, 2 do
        local targets = table.filter(room.alive_players, function(p) return not p:isNude() and player:isEnemy(p) end)
        if #targets > 0 then
          local to = table.random(targets)
          room:doIndicate(player, {to})
          room:throwCard(table.random(to:getCardIds("he")), skel.name, to, player)
          if not to.dead and forRandom(player, 0.2, "emot_jufeng") then
            room:damage { from = player, to = to, damage = 1, skillName = skel.name }
          end
        end
      end
    end
    if table.contains(cost_data, "emot_youbei") and not player.dead then -- 有备无患
      local cid = table.find(room.draw_pile, function (id) return player:canMoveCardIntoEquip(id, false) end)
      if cid then
        invokeTalent(player, "emot_youbei", event)
        room:moveCardIntoEquip(player, cid, skel.name, false)
      end
    end
    if table.contains(cost_data, "emot_jiejia") and not player.dead then -- 结痂
      local peach = cost_data["emot_jiejia_peach"] or 0
      if peach > 0 then
        invokeTalent(player, "emot_jiejia", event)
        room:changeMaxHp(player, peach)
        room:changeShield(player, peach)
      end
    end
    if table.contains(cost_data, "emot_yazi") then -- 睚眦必报
      invokeTalent(player, "emot_yazi", event)
      local yaziTos = cost_data["emot_yazi"] or {} ---@type ServerPlayer[]
      for _, to in ipairs(yaziTos) do
        if not to.dead then
          room:doIndicate(player, {to})
          room:delay(150)
          room:damage { from = player, to = to, damage = 1, skillName = skel.name }
        end
      end
    end
    if table.contains(cost_data, "emot_jingluo") and not player.dead then -- 鲸落
      local num = cost_data["emot_jingluo"] or 0
      room:addPlayerMark(player, "emot_jingluo", num)
      num = player:getMark("emot_jingluo") // 10
      if num > 0 then
        invokeTalent(player, "emot_jingluo", event)
        room:removePlayerMark(player, "emot_jingluo", num * 10)
        room:changeMaxHp(player, 1)
        if not player.dead then
          player:drawCards(2, skel.name)
        end
      end
    end
    if table.contains(cost_data, "emot_yifu") then -- 疫蝠
      local getNum = cost_data["emot_yifu"] or 0
      if getNum > 0 then
        room:addPlayerMark(player, "emot_yifu", getNum)
        local num = player:getMark("emot_yifu") // 5
        if num > 0 then
          invokeTalent(player, "emot_yifu", event)
          room:removePlayerMark(player, "emot_yifu", num * 5)
          for _ = 1, num do
            local to = getRandomEnemy()
            if not to then break end
            room:doIndicate(player, {to})
            room:delay(150)
            room:loseHp(to, 1, skel.name)
          end
        end
      end
    end
    if table.contains(cost_data, "emot_tanglang") then -- 铁镰螳螂
      local to = getRandomEnemy()
      if to ~= nil and forRandom(player, 0.2, "emot_tanglang") then
        invokeTalent(player, "emot_tanglang", event)
        room:doIndicate(player, {to})
        room:delay(150)
        room:damage { from = player, to = to, damage = 2, skillName = skel.name }
      end
    end
    if table.contains(cost_data, "emot_yiwen") then -- 疫蚊
      local num = cost_data["emot_yiwen"] or 0
      if num > 0 then
        room:addPlayerMark(player, "emot_yiwen", num)
        num = player:getMark("emot_yiwen") // 5
        if num > 0 then
          invokeTalent(player, "emot_yiwen", event)
          room:removePlayerMark(player, "emot_yiwen", num * 5)
          for _ = 1, num do
            local to = getRandomEnemy()
            if not to then break end
            room:doIndicate(player, {to})
            room:delay(150)
            room:loseHp(to, 1, skel.name)
          end
        end
      end
    end
    if table.contains(cost_data, "emot_shenjing") then -- 神经元件
      local to = getRandomEnemy()
      if to then
        invokeTalent(player, "emot_shenjing", event)
        room:doIndicate(player, {to})
        room:delay(150)
        room:damage { from = player, to = to, damage = 1, skillName = skel.name }
      end
    end
    --[[ -- 有BUG，先关了
    if hasTalent(player, "emot_yinhang") and not player.dead then
      local limit = 1
      local logged = false
      local nameMap, add = {}, {}
      for _, id in ipairs(player.player_cards[Player.Hand]) do
        local name = Fk:getCardById(id).name
        nameMap[name] = nameMap[name] or {}
        table.insert(nameMap[name], id)
      end
      for _, ids in pairs(nameMap) do
        if #ids > limit then
          table.insertTable(add, table.slice(ids, limit+1, #ids+1))
        end
      end
      if #add > 0 then
        logTalent(player, "emot_yinhang")
        logged = true
        player:addToPile("emot_yinhang", add, false, skel.name)
      end
      if not player.dead then
        nameMap = {}
        for _, id in ipairs(player.player_cards[Player.Hand]) do
          local name = Fk:getCardById(id).name
          nameMap[name] = nameMap[name] or {}
          table.insert(nameMap[name], id)
        end
        local bankMap = {}
        for _, id in ipairs(player:getPile("emot_yinhang")) do
          local name = Fk:getCardById(id).name
          bankMap[name] = bankMap[name] or {}
          table.insert(bankMap[name], id)
        end
        local get = {}
        for name, ids in pairs(bankMap) do
          local len = #(nameMap[name] or {})
          if len < limit then
            table.insertTable(get, table.slice(ids, 1, limit-len+1))
          end
        end
        if #get > 0 then
          if not logged then logTalent(player, "emot_yinhang") end
          room:obtainCard(player, get, false, fk.ReasonPrey, player, skel.name)
        end
      end
    end
    --]]
    handleInvokedTalents(player, event)
  end,
})

--- 用于判断移动信息
skel:addEffect(fk.AfterCardsMove, {
  can_refresh = function (self, event, target, player, data)
    return player.seat == 1
  end,
  on_refresh = function (self, event, target, player, data)
    local loseAllHand = {} -- 本次移动失去所有手牌的角色
    for _, move in ipairs(data) do
      if move.from and move.from:isKongcheng() and table.find(move.moveInfo, function(info)
        return info.fromArea == Card.PlayerHand
      end) then
        table.insertIfNeed(loseAllHand, move.from)
      end
    end
    if #loseAllHand > 0 then
      data.extra_data = data.extra_data or {}
      data.extra_data.loseAllHand = loseAllHand
    end
  end,
})

--- 摸牌前，注意这是任何摸牌都能触发
skel:addEffect(fk.BeforeDrawCard, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    if target == player then -- 我摸牌
      if hasTalent(player, "emot_yingtou") and data.num == 1 then -- 蝇头小利
        table.insert(cost_data, "emot_yingtou")
      end
      if player:getMark("emot_youhuo") > 0 then -- 诱惑
        table.insert(cost_data, "emot_youhuo")
      end
    end
    if hasTalent(player, "emot_kushu") and player:isEnemy(target) and not player.dead and data.num > 1 then -- 酷暑
      table.insert(cost_data, "emot_kushu")
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cost_data = event:getCostData(self) or {}
    if table.contains(cost_data, "emot_yingtou") then -- 蝇头小利
      invokeTalent(player, "emot_yingtou", event)
      data.num = data.num + 1
    end
    if table.contains(cost_data, "emot_kushu") then -- 酷暑
      invokeTalent(player, "emot_kushu", event)
      if forRandom(player, 0.2, "emot_kushu") then
        data.num = 0
      else
        data.num = data.num - 1
      end
    end
    if table.contains(cost_data, "emot_youhuo") then -- 诱惑
      invokeTalent(player, "emot_youhuo", event)
      data.num = data.num + player:getMark("emot_youhuo")
      room:setPlayerMark(player, "emot_youhuo", 0)
    end
    handleInvokedTalents(player, event)
  end,
})


--- 摸牌阶段的额定摸牌数
skel:addEffect(fk.DrawNCards, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    if target == player then -- 我的摸牌阶段
      for _, t in ipairs({"emot_wuming", "emot_beastking", "emot_caizhu", "emot_shenzi"}) do -- 兽王，无名之辈，土财主，神子
        if hasTalent(player, t) then
          table.insert(cost_data, t)
        end
      end
      if player:getMark("emot_ziyang_draw") > 0 then -- 滋养
        table.insert(cost_data, "emot_ziyang")
      end
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cost_data = event:getCostData(self) or {}
    if table.contains(cost_data, "emot_wuming") then -- 无名之辈
      invokeTalent(player, "emot_wuming", event)
      local num = #table.filter(getTalents(player), function (t)
        return t == "emot_wuming"
      end)
      data.n = data.n + num
    end
    if table.contains(cost_data, "emot_ziyang") then -- 滋养
      invokeTalent(player, "emot_ziyang", event, 1)
      data.n = data.n + player:getMark("emot_ziyang_draw")
    end
    if table.contains(cost_data, "emot_beastking") then -- 兽王
      invokeTalent(player, "emot_beastking", event, 1)
      data.n = data.n + #getTalents(player, "beast")
    end
    if table.contains(cost_data, "emot_caizhu") then -- 土财主
      invokeTalent(player, "emot_caizhu", event)
      local judge = {
        who = player,
        reason = "emot_caizhu",
        pattern = ".",
      }
      room:judge(judge)
      if judge.card then
        data.n = data.n + judge.card.number
      end
    end
    if table.contains(cost_data, "emot_shenzi") and not player.dead then -- 神子
      invokeTalent(player, "emot_shenzi", event)
      while not player.dead do
        data.n = data.n + 1
        local judge = {
          who = player,
          reason = "emot_shenzi",
          pattern = ".|.|^spade",
        }
        room:judge(judge)
        if not judge:matchPattern() then break end
      end
    end
    handleInvokedTalents(player, event)
  end,
})

